package com.doyoo.controller;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.doyoo.common.ResponseResult;
import com.doyoo.entity.JobInfo;
import com.doyoo.entity.JobStep;
import com.doyoo.entity.K8sJob;
import com.doyoo.enums.State;
import com.doyoo.enums.Type;
import com.doyoo.service.JobInfoService;
import com.doyoo.service.JobStepService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.mysql.cj.conf.ConnectionUrlParser;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.BatchV1Api;
import io.kubernetes.client.openapi.models.V1JobList;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.mysql.cj.conf.ConnectionUrlParser.Pair;

import javax.validation.constraints.Min;

/**
 * 定时任务 前端控制器
 */
@Tag(name = "任务(JobInfo)")
@RestController
public class JobInfoController {

    @Autowired
    private JobInfoService jobInfoService;

    @Autowired
    private JobStepService jobStepService;

    @Autowired
    private BatchV1Api batchV1Api;

    @Operation(summary = "任务类型列表")
    @GetMapping("/job-info-types")
    public ResponseResult<List<Pair<String, String>>> listTypes() {
        List<Pair<String, String>> typeList = Arrays.stream(Type.values())
                .map(e -> new ConnectionUrlParser.Pair<>(e.name(), e.getName()))
                .collect(Collectors.toList());
        return ResponseResult.success(typeList);
    }

    @Operation(summary = "任务状态列表")
    @GetMapping("/job-info-states")
    public ResponseResult<List<Pair<String, String>>> listStates() {
        List<Pair<String, String>> stateList = Arrays.stream(State.values())
                .map(e -> new Pair<>(e.name(), e.getName()))
                .collect(Collectors.toList());
        return ResponseResult.success(stateList);
    }

    @Operation(summary = "任务列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageIndex", value = "页码(从1开始)", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "pageSize", value = "页大小", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "name", value = "按job名称查询", dataTypeClass = String.class),
            @ApiImplicitParam(name = "type", value = "按job类型查询", dataTypeClass = String.class),
            @ApiImplicitParam(name = "state", value = "按job状态查询", dataTypeClass = String.class),
            @ApiImplicitParam(name = "env", value = "按env查询", dataTypeClass = String.class)
    })
    @GetMapping("/job-infos")
    public ResponseResult<Page<JobInfo>> list(
            @RequestParam(required = false) String name,
            @RequestParam(required = false) String type,
            @RequestParam(required = false) String state,
            @RequestParam(required = false) String env,
            @RequestParam @Min(value = 1, message = "页码不能小于1") Integer pageIndex,
            @RequestParam @Min(value = 1, message = "页大小不能小于1") Integer pageSize) {

        Page<JobInfo> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<JobInfo> queryWrapper = Wrappers.<JobInfo>lambdaQuery()
                .eq(StringUtils.isNotEmpty(name), JobInfo::getName, name)
                .eq(StringUtils.isNotEmpty(type), JobInfo::getType, EnumUtils.getEnum(Type.class, type))
                .eq(StringUtils.isNotEmpty(state), JobInfo::getState, EnumUtils.getEnum(State.class, state))
                .eq(StringUtils.isNotEmpty(env), JobInfo::getEnvs, env);

        return ResponseResult.success(jobInfoService.page(page, queryWrapper));
    }

    @Operation(summary = "任务-添加单个")
    @PostMapping("/job-infos")
    public ResponseResult addOne(@RequestBody JobInfo jobInfo) {
        jobInfoService.addOne(jobInfo);
        return ResponseResult.success();
    }

    @Operation(summary = "任务-查询单个")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "任务id", dataTypeClass = Integer.class)})
    @GetMapping("/job-infos/{id}")
    public ResponseResult<JobInfo> getOne(@PathVariable Integer id) {
        JobInfo jobInfo = jobInfoService.getById(id);
        List<JobStep> stepList = jobStepService.list(Wrappers.<JobStep>lambdaQuery()
                .eq(JobStep::getJobId, id)
                .orderByAsc(JobStep::getId));
        jobInfo.setStepList(stepList);
        return ResponseResult.success(jobInfo);
    }

    @Operation(summary = "任务-更新单个")
    @PutMapping("/job-infos/{id}")
    public ResponseResult updateOne(@PathVariable Integer id, @RequestBody JobInfo jobInfo) {
        jobInfo.setId(id);
        jobInfoService.updateOne(jobInfo);
        return ResponseResult.success();
    }

    @Operation(summary = "任务-启用")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "任务id", dataTypeClass = Integer.class)})
    @PostMapping("/job-infos/{id}/enable-requests")
    public ResponseResult enableOne(@PathVariable Integer id) throws JsonProcessingException, ApiException {
        jobInfoService.enableOne(id);
        return ResponseResult.success();
    }

    @Operation(summary = "任务-禁用")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "任务id", dataTypeClass = Integer.class)})
    @PostMapping("/job-infos/{id}/disable-requests")
    public ResponseResult disableOne(@PathVariable Integer id) throws ApiException {
        jobInfoService.disableOne(id);
        return ResponseResult.success();
    }

    @Operation(summary = "任务-查看执行记录")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "作业id", dataTypeClass = Integer.class)})
    @GetMapping("/job-infos/{id}/jobs")
    public ResponseResult<List<K8sJob>> getLogList(@PathVariable Integer id) throws ApiException {
        JobInfo jobInfo = jobInfoService.getById(id);
        if (jobInfo == null) {
            throw new RuntimeException("未找到作业");
        }
        String namespace = StringUtils.defaultString(jobInfo.getEnvs(), "default");
        V1JobList v1JobList = batchV1Api.listNamespacedJob(namespace, null, null, null, null, null, null, null, null, null);
        List<K8sJob> jobList = v1JobList.getItems().stream()
                .filter(v1Job -> v1Job.getMetadata().getName().startsWith(jobInfo.getName() + "-"))
                .map(v1Job -> K8sJob.builder()
                        .namespace(v1Job.getMetadata().getNamespace())
                        .name(v1Job.getMetadata().getName())
                        .startTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(v1Job.getStatus().getStartTime().getMillis()), ZoneId.of("Asia/Shanghai")))
                        .completionTime(LocalDateTime.ofInstant(Instant.ofEpochMilli(v1Job.getStatus().getCompletionTime().getMillis()), ZoneId.of("Asia/Shanghai")))
                        .succeeded(v1Job.getStatus().getSucceeded())
                        .build())
                .collect(Collectors.toList());

        return ResponseResult.success(jobList);
    }
}
